/*
 * @Author: duapple
 * @Date: 2021-10-16 18:24:15
 * @LastEditTime: 2021-10-17 18:19:10
 * @LastEditors: duapple
 * @Description: Add description
 * @FilePath: \tcp_server\main.go
 * Copyright (c) 2011 duapple - All rights reserved.
 */
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"time"
)

func main() {

	// read resp json file
	context, err := ioutil.ReadFile("./resp.json")
	if err != nil {
		log.Println(err)
		return
	}

	var resp map[string]interface{}
	err = json.Unmarshal(context, &resp)
	if err != nil {
		log.Println(err)
		return
	}

	service, ok := resp["server"].(string)
	if !ok || service == "" {
		return
	}
	log.Println("tcp server: ", service)

	tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
	checkError(err)
	listener, err := net.ListenTCP("tcp", tcpAddr)
	checkError(err)
	for {
		conn, err := listener.Accept()
		if err != nil {
			continue
		}
		go handleClient(conn)
	}
}

func handleClient(conn net.Conn) {
	log.Println("tcp connected: ", conn.RemoteAddr())
	conn.SetReadDeadline(time.Now().Add(999999 * time.Minute)) // set 2 minutes timeout
	request := make([]byte, 128)                               // set maxium request length to 128B to prevent flood attack
	defer conn.Close()                                         // close connection before exit

	// read resp json file
	context, err := ioutil.ReadFile("./resp.json")
	if err != nil {
		log.Println(err)
		return
	}

	var resp map[string]interface{}
	err = json.Unmarshal(context, &resp)
	if err != nil {
		log.Println(err)
		return
	}
	log.Println("sleep delay: ", resp["sleep"].(float64), "ms\n ")

	for {
		request = make([]byte, 256) // clear last read content
		read_len, err := conn.Read(request)

		if read_len == 0 {
			log.Println("tcp disconnected: ", conn.RemoteAddr())
			break
		}

		fmt.Println()
		log.Println("request: ", string(request))

		for i := read_len - 1; i >= 0; i-- {
			if request[i] == 0x00 || request[i] == 0x0a || request[i] == 0x0d {
				request = request[:i]
				read_len--
			} else {
				break
			}
		}

		var req map[string]interface{}
		err = json.Unmarshal(request[:read_len], &req)
		if err != nil {
			log.Println(err)
			continue
		}

		jsonStr, err := json.Marshal(resp[req["cmd"].(string)])
		if err != nil || string(jsonStr) == "null" {
			log.Println(err)
			continue
		}

		log.Println("resp msg: ", string(jsonStr))
		if t, ok := resp["sleep"].(float64); ok || t != 0 {
			time.Sleep(time.Duration(t) * time.Millisecond)
		}
		conn.Write([]byte(jsonStr))
	}
}

func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
		os.Exit(1)
	}
}
